//// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
//package com.linqingying.gitcode.pullrequest.ui.editor
//
//import com.intellij.collaboration.async.*
//import com.intellij.collaboration.ui.codereview.diff.DiscussionsViewOption
//import com.intellij.collaboration.util.*
//import com.intellij.diff.util.LineRange
//import com.intellij.diff.util.Range
//import com.intellij.diff.util.Side
//import com.intellij.openapi.diagnostic.logger
//import com.intellij.openapi.diff.impl.patch.PatchHunkUtil
//import com.intellij.openapi.diff.impl.patch.TextFilePatch
//import com.intellij.openapi.diff.impl.patch.withoutContext
//import com.intellij.openapi.progress.coroutineToIndicator
//import com.intellij.openapi.project.Project
//import com.intellij.openapi.util.text.StringUtil
//import com.intellij.platform.util.coroutines.childScope
//import git4idea.changes.GitTextFilePatchWithHistory
//import git4idea.changes.createVcsChange
//import kotlinx.coroutines.CoroutineScope
//import kotlinx.coroutines.flow.*
//import com.linqingying.gitcode.api.data.pullrequest.GCPullRequestReviewThread
//import com.linqingying.gitcode.api.data.pullrequest.isVisible
//import com.linqingying.gitcode.api.data.pullrequest.mapToLocation
//import com.linqingying.gitcode.pullrequest.data.provider.GCPRDataProvider
//import com.linqingying.gitcode.pullrequest.data.provider.createThreadsRequestsFlow
//import com.linqingying.gitcode.pullrequest.ui.comment.GCPRReviewCommentLocation
//import com.linqingying.gitcode.pullrequest.ui.comment.GCPRReviewCommentPosition
//import com.linqingying.gitcode.pullrequest.ui.comment.GCPRThreadsViewModels
//
//interface GCPRReviewFileEditorViewModel {
//  val originalContent: StateFlow<ComputedResult<CharSequence>?>
//  val changedRanges: List<Range>
//
//  fun getBaseContent(lines: LineRange): String?
//
//  val canComment: Boolean
//  val commentableRanges: List<Range>
//
//  val threads: StateFlow<Collection<GCPRReviewFileEditorThreadViewModel>>
//  val newComments: StateFlow<Collection<GCPRReviewFileEditorNewCommentViewModel>>
//
//  val linesWithComments: StateFlow<Set<Int>>
//
//  fun requestNewComment(lineIdx: Int, focus: Boolean)
//  fun cancelNewComment(lineIdx: Int)
//
//  fun showDiff(lineIdx: Int?)
//}
//
//private val LOG = logger<GCPRReviewFileEditorViewModelImpl>()
//
//internal class GCPRReviewFileEditorViewModelImpl(
//  project: Project,
//  parentCs: CoroutineScope,
//  dataProvider: GCPRDataProvider,
//  private val change: RefComparisonChange,
//  private val diffData: GitTextFilePatchWithHistory,
//  private val threadsVms: GCPRThreadsViewModels,
//  private val discussionsViewOption: StateFlow<DiscussionsViewOption>,
//  private val showDiff: (change: RefComparisonChange, lineIdx: Int?) -> Unit
//) : GCPRReviewFileEditorViewModel {
//  private val cs = parentCs.childScope(classAsCoroutineName())
//
//  override val originalContent: StateFlow<ComputedResult<CharSequence>?> =
//    flow {
//      computeEmitting {
//        coroutineToIndicator {
//          change.createVcsChange(project).afterRevision?.content ?: ""
//        }.let {
//          StringUtil.convertLineSeparators(it)
//        }
//      }?.onFailure {
//        LOG.warn("Couldn't load head content for $change", it)
//      }
//    }.stateIn(cs, SharingStarted.Lazily, ComputedResult.loading())
//
//  override val changedRanges: List<Range> = diffData.patch.hunks.withoutContext().toList()
//
//  override fun getBaseContent(lines: LineRange): String? {
//    if (lines.start == lines.end) return ""
//    return PatchHunkUtil.getLinesLeft(diffData.patch, lines)
//  }
//
//  override val canComment: Boolean = dataProvider.reviewData.canComment()
//  override val commentableRanges: List<Range> = diffData.patch.ranges
//
//  private val mappedThreads: StateFlow<Map<String, MappedGCPRReviewEditorThreadViewModel.MappingData>> =
//    dataProvider.reviewData.createThreadsRequestsFlow()
//      .computationState()
//      .transformConsecutiveSuccesses(false) {
//        combine(discussionsViewOption) { threads, viewOption ->
//          threads.associateBy(GCPullRequestReviewThread::id) { threadData ->
//            val isVisible = threadData.isVisible(viewOption)
//            val line = threadData.mapToLocation(diffData, Side.RIGHT)?.takeIf { (side, _) -> side == Side.RIGHT }?.second
//            MappedGCPRReviewEditorThreadViewModel.MappingData(isVisible, line)
//          }
//        }
//      }.map { it.getOrNull().orEmpty() }.stateInNow(cs, emptyMap())
//
//  override val threads: StateFlow<Collection<GCPRReviewFileEditorThreadViewModel>> =
//    threadsVms.compactThreads.mapModelsToViewModels { sharedVm ->
//      MappedGCPRReviewEditorThreadViewModel(this, sharedVm, mappedThreads.mapNotNull { it[sharedVm.id] })
//    }.stateInNow(cs, emptyList())
//
//  override val linesWithComments: StateFlow<Set<Int>> =
//    mappedThreads.map {
//      it.values.mapNotNullTo(mutableSetOf()) { (isVisible, location) -> location?.takeIf { isVisible } }
//    }.stateInNow(cs, emptySet())
//
//  private val newCommentsContainer =
//    MappingScopedItemsContainer.byIdentity<GCPRReviewNewCommentEditorViewModel, GCPRReviewFileEditorNewCommentViewModel>(cs) {
//      GCPRReviewFileEditorNewCommentViewModelImpl(it.position.location.lineIdx, it)
//    }
//  override val newComments: StateFlow<Collection<GCPRReviewFileEditorNewCommentViewModel>> =
//    newCommentsContainer.mappingState.mapState { it.values }
//
//  init {
//    cs.launchNow {
//      threadsVms.newComments.collect { comments ->
//        val commentsForChange = comments.values.filter { it.position.change == change && it.position.location.side == Side.RIGHT }
//        newCommentsContainer.update(commentsForChange)
//      }
//    }
//  }
//
//  override fun requestNewComment(lineIdx: Int, focus: Boolean) {
//    val position = GCPRReviewCommentPosition(change, GCPRReviewCommentLocation.SingleLine(Side.RIGHT, lineIdx))
//    val sharedVm = threadsVms.requestNewComment(position)
//    if (focus) {
//      cs.launchNow {
//        newCommentsContainer.addIfAbsent(sharedVm).requestFocus()
//      }
//    }
//  }
//
//  override fun cancelNewComment(lineIdx: Int) {
//    val position = GCPRReviewCommentPosition(change, GCPRReviewCommentLocation.SingleLine(Side.RIGHT, lineIdx))
//    threadsVms.cancelNewComment(position)
//  }
//
//  override fun showDiff(lineIdx: Int?) {
//    showDiff(change, lineIdx)
//  }
//}
//
//private val TextFilePatch.ranges: List<Range>
//  get() = hunks.map(PatchHunkUtil::getRange)
